package test.myorm.core;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.google.common.collect.ImmutableMap;

import jodd.bean.BeanUtilBean;
import test.myorm.demo.User;
import test.myorm.demo.mapper.UserMapper;
import test.myorm.executor.Executor;

public class SqlSession {
	
	private Configuration configuration;
	private Executor executor;
	
	public SqlSession(Configuration configuration, Executor executor) {
		this.configuration = configuration;
		this.executor = executor;
	}
	
	public Object getMapper(Class<?> clazz) {
		//代理可以由SqlSessionCreater统一先创建出来，然后这里直接拿
		return configuration.getMapperProxy(clazz.getName());
	}
	
	public List selectList(String key, Object...params) {
		Sql sql = getSql(key, params);
		try {
			return executor.selectList(sql);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public Object selectOne(String key, Object...params) {
		Sql sql = getSql(key, params);
		try {
			return executor.selectOne(sql);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public int update(String key, Object...params) {
		Sql sql = getSql(key, params);
		try {
			return executor.update(sql);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public int insert(String key, Object...params) {
		Sql sql = getSql(key, params);
		try {
			return executor.update(sql);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public int delete(String key, Object...params) {
		Sql sql = getSql(key, params);
		try {
			return executor.update(sql);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	private Sql getSql(String key, Object...params) {
		boolean sqlExists = configuration.getSqlMap().containsKey(key);
		if(!sqlExists) {
			throw new RuntimeException("错误的key[" + key + "]!!!");
		}
		Sql sql = configuration.getSqlMap().get(key);
		
		if(params.length > 1) {
			for(Object param : params) {
				if(!Parameter.baseClasses.contains(param.getClass())) {
					throw new RuntimeException("多参数不支持复杂类型!!!");
				}
			}
		}
		
		Parameter parameter = sql.getParameter();
		parameter.setOrgParam(params);
		int size = parameter.getSize();
		
		if(params.length > 1) {
			if(params.length != size) {
				throw new RuntimeException("参数个数[" + params.length + "]与mapper[" + size + "[不匹配!!!");
			}
			parameter.setParamList(Arrays.asList(params));
		} else if(params.length==1) {
			Object param = params[0];
			Class paramClass = param.getClass();
			Class parameterClass = parameter.getClazz();
			int parameterType = parameter.getType();
			if(parameterClass!=null && !parameterClass.equals(paramClass)) {
				throw new RuntimeException("传参["+ paramClass +"]与mapper定义参数[" + parameterClass + "]类型不符!!!");
			}
			if(Parameter.baseClasses.contains(paramClass)) {
				parameter.setParamList(Arrays.asList(param));
			} else if(paramClass.isArray()) {
				
			} else if(List.class.isAssignableFrom(paramClass)) {
				if(parameterType==Parameter.NAME) {
					throw new RuntimeException("name式传参不支持List的参数类型!!!");
				} else if(parameterType==Parameter.QUESMARK) {
					parameter.setParamList((List)param);
				}
			} else if(Map.class.isAssignableFrom(paramClass) ) {
				Map mapParam = (Map)param;
				if(mapParam.size()!=size) {
					throw new RuntimeException("参数个数与mapper不匹配!!!");
				}
				if(parameterType==Parameter.QUESMARK) {
					if(!LinkedHashMap.class.isAssignableFrom(paramClass)) {
						throw new RuntimeException("name式传参对于map型参数只接受LinkedHashMap!!!");
					}
					List paramList = new ArrayList();
					for(Object obj : mapParam.entrySet()) {
						Map.Entry entry = (Entry) obj;
						paramList.add(entry.getValue());
					}
					parameter.setParamList(paramList);
				} else if(parameterType==Parameter.NAME) {
					List paramList = new ArrayList();
					List<String> keyList = parameter.getKeyList();
					for(String paramKey : keyList) {
						paramList.add(mapParam.get(paramKey));
					}
					parameter.setParamList(paramList);
				}
			} else {
				//javabean
				BeanUtilBean bub = new BeanUtilBean();
				Class beanClass = param.getClass();
				Field[] fields = beanClass.getDeclaredFields();
				if(parameterType==Parameter.QUESMARK) {
					List paramList = new ArrayList();
					for(Field field : fields) {
						paramList.add(bub.getProperty(param, field.getName()));
					}
					parameter.setParamList(paramList);
				} else if(parameterType==Parameter.NAME) {
					List paramList = new ArrayList();
					List<String> keyList = parameter.getKeyList();
					for(String paramKey : keyList) {
						boolean exists = bub.hasProperty(param, paramKey);
						paramList.add(exists?bub.getProperty(param, paramKey) : null);
					}
					parameter.setParamList(paramList);
				}
			}
		}
		
		return sql;
	}
	
	static class Builder {
		
		public SqlSession build(Configuration configuration) {
			Executor executor = new Executor(configuration);
			return new SqlSession(configuration, executor);
		}
		
	}
	
	public static void main(String[] args) {
		SqlSession sqlSession = new SqlSessionCreater("config").build();
////		SqlSession sqlSession = new SqlSession.Builder().build(configuration);
//		List list = sqlSession.selectList("test.myorm.demo.mapper.UserMapper.getUserByAge", 10);
//		System.out.println(list);
//		Object obj = sqlSession.selectOne("test.myorm.demo.mapper.UserMapper.getUserById", 1);
//		System.out.println(obj);
//		
//		obj = sqlSession.selectOne("test.myorm.demo.mapper.UserMapper.getUserByNameAndAge", 10, "zhangsan");
//		System.out.println(obj);
//		
		UserMapper userMapper = (UserMapper) sqlSession.getMapper(UserMapper.class);
//		User user = userMapper.getUserById(1);
//		System.out.println(user);
//		System.out.println("⭐️ 棒乄棒⭐️ ".length());
		
//		User user = new User();
//		user.setAge(44);
//		user.setName("hdddddddddddddddddddejhdei");
////		int column = sqlSession.update("test.myorm.demo.mapper.UserMapper.addUser", user);
//		int column = userMapper.addUser(user);
//		System.out.println(column);
//		System.out.println(user);
		
		Map userMap = new HashMap();
		userMap.put("age", 33);
		userMap.put("name", "laddddowang");
		int column = userMapper.addUserMap(userMap);
		System.out.println(column);
		System.out.println(userMap);
		
//		User user = new User();
//		user.setId(1);
//		user.setAge(88);
//		user.setName("feng");
//		int column = userMapper.updateUser(user);
//		System.out.println(column);
	}
}
